<!DOCTYPE HTML>
<html lang="zh-CN">

<head>
    <!--Setting-->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta http-equiv="Cache-Control" content="no-siteapp">
    <meta http-equiv="Cache-Control" content="no-transform">
    <meta name="renderer" content="webkit|ie-comp|ie-stand">
    <meta name="apple-mobile-web-app-capable" content="涛哥的博客">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    <meta name="browsermode" content="application">
    <meta name="screen-orientation" content="portrait">
    <meta name="theme-version" content="1.2.3">
    <meta name="root" content="/">
    <link rel="dns-prefetch" href="https://jaredtao.github.io">
    <!--SEO-->

<meta name="keywords" content="Qt,Qml,QtQuick,组件化编程" />


<meta name="description" content="
简介
源码
C++访问Qml
findChild
QQmlComponent


Qml访问C++
注册类并使用
注册实例并使用



简介本文是《玩转Qml》系列文章的第五篇，涛哥将教大家，..." />


<meta name="robots" content="all" />
<meta name="google" content="all" />
<meta name="googlebot" content="all" />
<meta name="verify" content="all" />
    <!--Title-->

<title>
    
    玩转Qml(5)-Qml与C++交互 |
    
    涛哥的博客
</title>

<link rel="alternate" href="/atom.xml" title="涛哥的博客" type="application/atom+xml">


<link rel="icon" href="/favicon.ico">

    


<link rel="stylesheet" href="/css/bootstrap.min.css?rev=3.3.7.css">
<link rel="stylesheet" href="/css/font-awesome.min.css?rev=4.7.0.css">
<link rel="stylesheet" href="/css/style.css?rev=@@hash.css">

    
<div class="hide">
    <script type="text/javascript">
    var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");
    document.write(unescape("%3Cspan class='cnzz_stat_icon_1263868967 hide' %3E%3Cscript%20src%3D%22https%3A%2F%2Fs95.cnzz.com%2Fz_stat.php%3Fweb_id%3D1272564536%22%3E%3C%2Fscript%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s19.cnzz.com/z_stat.php%3Fid%3D1263868967%26show%3Dpic1' type='text/javascript'%3E%3C/script%3E"));
    </script>
</div>




    

<script>
(function() {
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
    } else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script>

<meta name="generator" content="Hexo 4.2.1"></head>
<!--[if lte IE 8]>
<style>
    html{ font-size: 1em }
</style>
<![endif]-->
<!--[if lte IE 9]>
<div style="ie">你使用的浏览器版本过低，为了你更好的阅读体验，请更新浏览器的版本或者使用其他现代浏览器，比如Chrome、Firefox、Safari等。</div>
<![endif]-->
<body>
    <header class="main-header"  style="background-image:url(
    http://snippet.shenliyang.com/img/banner.jpg)"
     >
    <div class="main-header-box">
        <a class="header-avatar" href="/" title='JaredTao'>
            <img src="/img/avatar.jpg" alt="logo头像" class="img-responsive center-block">
        </a>
        <div class="branding">
            <!--<h2 class="text-hide">Snippet主题,从未如此简单有趣</h2>-->
            
            <h2>
                单枪匹马亦对饮，历经磨难记初心
            </h2>
            
        </div>
    </div>
</header>
    <nav class="main-navigation">
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <div class="navbar-header"><span class="nav-toggle-button collapsed pull-right" data-toggle="collapse" data-target="#main-menu" id="mnav">
                        <span class="sr-only"></span>
                        <i class="fa fa-bars"></i>
                    </span>
                    <a class="navbar-brand" href="https://jaredtao.github.io">
                        涛哥的博客</a>
                </div>
                <div class="collapse navbar-collapse" id="main-menu">
                    <ul class="menu">
                        
                        <li role="presentation" class="text-center">
                            <a href="/"><i class="fa "></i>
                                首页</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/玩转Qt/"><i class="fa "></i>
                                玩转Qt</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/玩转Qml/"><i class="fa "></i>
                                玩转Qml</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/玩转QtQuick/"><i class="fa "></i>
                                玩转QtQuick</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/categories/涛哥的博客/"><i class="fa "></i>
                                涛哥的博客</a>
                        </li>
                        
                        <li role="presentation" class="text-center">
                            <a href="/archives/"><i class="fa "></i>
                                时间轴</a>
                        </li>
                        
                    </ul>
                </div>
            </div>
        </div>
    </div>
</nav>
    <section class="content-wrap">
        <div class="container">
            <div class="row">
                <main class="col-md-8 main-content m-post">
                    <p id="process"></p>
<article class="post">
    <div class="post-head">
        <h1 id="玩转Qml(5)-Qml与C++交互">
            
            玩转Qml(5)-Qml与C++交互
            
        </h1>
        <div class="post-meta">
    
    <span class="categories-meta fa-wrap">
        <i class="fa fa-folder-open-o"></i>
        <a class="category-link" href="/categories/%E7%8E%A9%E8%BD%ACQml/">玩转Qml</a>
    </span>
    
    
    <span class="fa-wrap">
        <i class="fa fa-tags"></i>
        <span class="tags-meta">
            
            <a class="tag-link" href="/tags/Qml/" rel="tag">Qml</a> <a class="tag-link" href="/tags/Qt/" rel="tag">Qt</a> <a class="tag-link" href="/tags/QtQuick/" rel="tag">QtQuick</a> <a class="tag-link" href="/tags/%E7%BB%84%E4%BB%B6%E5%8C%96%E7%BC%96%E7%A8%8B/" rel="tag">组件化编程</a>
            
        </span>
    </span>
    
    
    
    <span class="fa-wrap">
        <i class="fa fa-clock-o"></i>
        <span class="date-meta">
            2019/05/17</span>
    </span>
    
    <span class="fa-wrap">
        <i class="fa fa-eye"></i>
        <span id="busuanzi_value_page_pv"></span>
    </span>
    
    
</div>
        
        
        <p class="fa fa-exclamation-triangle warning">
            本文于<strong>
                2033</strong>
            天之前发表，文中内容可能已经过时。
        </p>
        
    </div>
    
<div id="post-gallery">
    
    <img src="/img/avatar.jpg" alt="gallery-img" class="gallery">
    
</div>

    <div class="post-body post-content">
        <ul>
<li><a href="#简介">简介</a></li>
<li><a href="#源码">源码</a></li>
<li><a href="#c访问qml">C++访问Qml</a><ul>
<li><a href="#findchild">findChild</a></li>
<li><a href="#qqmlcomponent">QQmlComponent</a></li>
</ul>
</li>
<li><a href="#qml访问c">Qml访问C++</a><ul>
<li><a href="#注册类并使用">注册类并使用</a></li>
<li><a href="#注册实例并使用">注册实例并使用</a></li>
</ul>
</li>
</ul>
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>本文是《玩转Qml》系列文章的第五篇，涛哥将教大家，Qml与C++的交互。</p>
<p>Qml已经有很多功能，不过终归会有不够用或不适用的地方，需要通过与C++的交互进行功能扩展。</p>
<p>这回涛哥尝试把所有Qml与C++交互相关的知识点都写出来，做一个透彻、全面的总结。</p>
<h2 id="源码"><a href="#源码" class="headerlink" title="源码"></a>源码</h2><p>《玩转Qml》系列文章，配套了一个优秀的开源项目:TaoQuick</p>
<p>github <a href="https://github.com/jaredtao/TaoQuick" target="_blank" rel="noopener">https://github.com/jaredtao/TaoQuick</a></p>
<p>访问不了或者速度太慢，可以用国内的镜像网站gitee</p>
<p><a href="https://gitee.com/jaredtao/TaoQuick" target="_blank" rel="noopener">https://gitee.com/jaredtao/TaoQuick</a></p>
<h2 id="C-访问Qml"><a href="#C-访问Qml" class="headerlink" title="C++访问Qml"></a>C++访问Qml</h2><p>c++访问Qml有两种方式： findChild和 QQmlComponent。</p>
<h3 id="findChild"><a href="#findChild" class="headerlink" title="findChild"></a>findChild</h3><p>了解Qt的人都知道，Qt的很多对象是QObject的子类，这些QObject只要设置了parent，就是有父子关系的，会产生一棵 “对象树”。</p>
<p>只要有了根节点，树上的任意节点都可以通过findChild的方式获取到。</p>
<p>写个简单的TaoObject，来示意一下:</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">TaoObject</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//构造函数，传递parent进来</span></span><br><span class="line">    TaoObject(TaoObject *parent = <span class="literal">nullptr</span>) : m_pParent(parent)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (m_pParent)</span><br><span class="line">        &#123;</span><br><span class="line">            m_pParent-&gt;appendChild(<span class="keyword">this</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//析构函数，析构children。即子对象自动回收机制。</span></span><br><span class="line">    ~TaoObject()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> *pObj : m_children)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> pObj;</span><br><span class="line">        &#125;</span><br><span class="line">        m_children.<span class="built_in">clear</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//获取name</span></span><br><span class="line">    <span class="function"><span class="keyword">const</span> QString &amp;<span class="title">getName</span><span class="params">()</span> <span class="keyword">const</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> m_name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//设置name</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setName</span><span class="params">(<span class="keyword">const</span> QString &amp;name)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//查找子Object</span></span><br><span class="line">    <span class="function">TaoObject *<span class="title">findChild</span><span class="params">(<span class="keyword">const</span> QString &amp;name)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="comment">//先检查自己的名字，是否匹配目标名字</span></span><br><span class="line">        <span class="keyword">if</span> (m_name == name)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//遍历子Object，查找</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> pObj : m_children)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">//递归调用，深度优先的搜索</span></span><br><span class="line">            <span class="keyword">auto</span> resObj = pObj-&gt;findChild(name);</span><br><span class="line">            <span class="keyword">if</span> (resObj)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">return</span> resObj;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">appendChild</span><span class="params">(TaoObject *child)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_children.push_back(child);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="comment">//存储名字</span></span><br><span class="line">    QString m_name;</span><br><span class="line">    <span class="comment">//子对象列表</span></span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;TaoObject *&gt; m_children;</span><br><span class="line">    <span class="comment">//父对象指针</span></span><br><span class="line">    TaoObject *m_pParent = <span class="literal">nullptr</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>Qml的基本元素,大多是继承于QQuickItem，而QQuickItem继承于QObject。</p>
<p>所以Qml大多数对象都是QObject的子类，也是可以通过findChild的方式获取到对象指针。</p>
<p>拿到了QObject，可以通过qobject_cast转换成具体的类型来使用，也可以直接用QObject的invok方法。</p>
<p>例如有如下Qml代码:</p>
<figure class="highlight qml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">Item</span> &#123;</span><br><span class="line">    <span class="attribute">id:</span><span class="string"> root</span></span><br><span class="line">    ...</span><br><span class="line">    <span class="title">Rectangle</span> &#123;</span><br><span class="line">        <span class="attribute">id:</span><span class="string"> centerRect</span></span><br><span class="line">        <span class="attribute">objectName</span>: <span class="string">"centerRect"</span>        <span class="comment">//必不可少的objectName</span></span><br><span class="line">        <span class="keyword">property</span><span class="string"> bool canSee</span>: visible   <span class="comment">//自定义属性，可以被C++ invok访问</span></span><br><span class="line">        <span class="keyword">signal</span><span class="string"> sayHello</span>()               <span class="comment">//自定义信号1，可以被C++ invok调用</span></span><br><span class="line">        <span class="keyword">signal</span><span class="string"> sayHelloTo</span>(name)         <span class="comment">//自定义信号2，带参数。可以被C++ invok调用。参数的名字要起好，后面通过这个名字来使用参数</span></span><br><span class="line">        <span class="function"><span class="keyword">function</span> <span class="title">rotateToAngle</span>(<span class="params">angle</span>)   //自定义<span class="title">js</span>函数，旋转至指定角度。可以被<span class="title">C</span>++ <span class="title">invok</span>调用。</span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">            rotation = angle</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>那么在C++ 中访问的方式是：</p>
<ul>
<li>如果用QQuickView加载qml，就是</li>
</ul>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">QQuickView view;</span><br><span class="line">...</span><br><span class="line">QObject *centerObj = view.rootObject()-&gt;findChild&lt;QObject *&gt;(<span class="string">"centerRect"</span>);</span><br><span class="line"><span class="keyword">if</span> (!centerObj) &#123; <span class="keyword">return</span>;&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>如果用QQmlEngine加载qml，就是<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">QQmlEngine engine;</span><br><span class="line">...</span><br><span class="line">QObject *centerObj = engine.rootObject()-&gt;findChild&lt;QObject *&gt;(<span class="string">"centerRect"</span>);</span><br><span class="line"><span class="keyword">if</span> (!centerObj) &#123; <span class="keyword">return</span>;&#125;</span><br></pre></td></tr></table></figure>
(QObject类型也可以换成QQuickItem 或者其它)</li>
</ul>
<p>拿到了对象指针，接下来就好办了</p>
<p>访问其属性</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bool</span> canSee = centerObj-&gt;property(<span class="string">"canSee"</span>).toBool();</span><br></pre></td></tr></table></figure>

<p>发射其信号(其实就是函数调用)</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">QObject::invokeMethod(centerObj, <span class="string">"sayHello"</span>);</span><br><span class="line">QObject::invokeMethod(centerObj, <span class="string">"sayHelloTo"</span>, Q_ARG(QString, <span class="string">"Tao"</span>))</span><br></pre></td></tr></table></figure>

<p>调用其js函数,可以传参数过去,可以取得返回值</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">bool</span> ok;</span><br><span class="line">QObject::invokeMethod(centerObj, <span class="string">"rotateToAngle"</span>, Q_RETURN_ARG(<span class="keyword">bool</span>, ok), Q_ARG(qreal <span class="number">180</span>));</span><br></pre></td></tr></table></figure>

<p>这里再补充一下, Qml中给自定义的信号写槽或连接到别的槽(Qml中的槽就是js函数):</p>
<figure class="highlight qml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">Item</span> &#123;</span><br><span class="line">    <span class="attribute">id:</span><span class="string"> root</span></span><br><span class="line">    ...</span><br><span class="line">    <span class="title">Rectangle</span> &#123;</span><br><span class="line">        <span class="attribute">id:</span><span class="string"> centerRect</span></span><br><span class="line">        <span class="attribute">objectName</span>: <span class="string">"centerRect"</span> <span class="comment">//必不可少的objectName</span></span><br><span class="line">        <span class="keyword">signal</span><span class="string"> sayHello</span>()       <span class="comment">//自定义信号1</span></span><br><span class="line">        <span class="keyword">signal</span><span class="string"> sayHelloTo</span>(name) <span class="comment">//自定义信号2，带参数。参数的名字要起好，后面通过这个名字来使用参数</span></span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">function</span> <span class="title">rotateToAngle</span>(<span class="params">angle</span>) //自定义<span class="title">js</span>函数，旋转至指定角度</span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">            rotation = angle</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">onSayHello</span>: &#123;               <span class="comment">//信号1的槽</span></span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">"hello"</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="attribute">onSayHelloTo</span>: &#123;             <span class="comment">//信号2的槽，直接用信号定义时的参数名字name作为关键字访问参数</span></span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">"hello"</span>, name)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="attribute">Component.onCompleted</span>: &#123; </span><br><span class="line">            <span class="comment">//信号2 连接到 root的函数。参数会自动匹配。</span></span><br><span class="line">            sayHello.connect(root.rootSayHello)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">rootSayHello</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"root: hello"</span>, name)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="QQmlComponent"><a href="#QQmlComponent" class="headerlink" title="QQmlComponent"></a>QQmlComponent</h3><p>C++中的QQmlComponent可以用来动态加载Qml文件，并可以创建多个实例，</p>
<p>对应Qml中的Component。Qml中还有一个Loader，也可以动态加载并创建单个实例。</p>
<p>(QQmlComponent这种方式不太多见，不过涛哥之前参与过开发一个框架，使用的就是QQmlComponent动态加载Qml，</p>
<p>完全在c++中控制界面的加载，加载效率、内存占用上都比纯Qml优秀。)</p>
<p>来看一个例子：</p>
<figure class="highlight qml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Circle.qml</span></span><br><span class="line"><span class="title">Rectangle</span> &#123;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">300</span></span><br><span class="line">    <span class="attribute">height</span>: width</span><br><span class="line">    <span class="attribute">radius</span>: width / <span class="number">2</span></span><br><span class="line">    <span class="attribute">color</span>: <span class="string">"red"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">QQmlEngine engine;</span><br><span class="line"><span class="function">QQmlComponent <span class="title">component</span><span class="params">(&amp;engine, QUrl::fromLocalFile(<span class="string">"Circle.qml"</span>))</span></span>;</span><br><span class="line"></span><br><span class="line">QObject *circleObject = component.create();</span><br><span class="line">QQuickItem *item = qobject_cast&lt;QQuickItem*&gt;(circleObject);</span><br><span class="line"><span class="keyword">int</span> <span class="built_in">width</span> = item-&gt;<span class="built_in">width</span>();</span><br></pre></td></tr></table></figure>
<p>拿到对象指针，就和前面的一样了，这里不再赘述了。</p>
<h2 id="Qml访问C"><a href="#Qml访问C" class="headerlink" title="Qml访问C++"></a>Qml访问C++</h2><p>Qml要访问C++的内容，需要先从C++把要访问的内容注册进Qml。</p>
<p>先说说能用哪些：</p>
<p>注册过后，Qml中可以访问的内容，包括 Q_INVOKABLE 修饰的函数、枚举、 QObject的属性 信号 槽</p>
<p>Q_INVOKABLE 函数可以用在普通的结构体或者类中，但是这种用法不常见/不方便。常见的是在QObject的子类中，给非槽函数设置为Q_INVOKABLE</p>
<p>枚举的注册Qt帮助文档很详细，而且5.10以后可以在qml中定义枚举了，这里涛哥就不展开了。</p>
<p>QObject的属性 信号 槽，都是可以通过注册后，在qml中使用的。信号、槽都可以带参数，槽可以有返回值。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BrotherTao</span> :</span> <span class="keyword">public</span> QObject </span><br><span class="line">&#123;</span><br><span class="line">    Q_OBJECT <span class="comment">//这个宏一定要写上。不写可能的后果是，moc生成失败，信号 槽实现不了，编译过不了。</span></span><br><span class="line">    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) <span class="comment">//自定义属性，操作包括： 读、写和通知。Qml可以读写、获取通知</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    ...</span><br><span class="line">    <span class="comment">//唱歌</span></span><br><span class="line">    <span class="function">Q_INVOKABLE <span class="keyword">void</span> <span class="title">sing</span><span class="params">()</span></span>;        <span class="comment">//invok函数，可以被Qml调用。可以带参数和返回值</span></span><br><span class="line"><span class="keyword">public</span> slots:</span><br><span class="line">    <span class="comment">//打游戏，参数为次数，返回值为得分。</span></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">playGame</span><span class="params">(<span class="keyword">int</span> count)</span></span>;        <span class="comment">//槽函数，可以被Qml调用。可以带参数和返回值</span></span><br><span class="line"></span><br><span class="line">signals:</span><br><span class="line">    <span class="comment">//肚子饿了。参数为想吃的东西。</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">hungry</span><span class="params">(<span class="keyword">const</span> QString &amp;foodName)</span></span>;                  <span class="comment">//信号，可以被Qml接收。</span></span><br><span class="line">    ...</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>这里要说的是，属性、函数参数、返回值的类型，都需要是Qml能识别的类型。</p>
<p>Qt的常用类型已经在Qt内部注册好了，自定义的需要单独注册。</p>
<p>再说说怎么用：</p>
<p>注册分为两种：注册类型和注册实例。</p>
<h3 id="注册类并使用"><a href="#注册类并使用" class="headerlink" title="注册类并使用"></a>注册类并使用</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">qmlRegisterTyle&lt;BrotherTao&gt;(<span class="string">"BrotherTao"</span>,<span class="number">1</span>, <span class="number">0</span>, <span class="string">"BrotherTao"</span>);</span><br></pre></td></tr></table></figure>
<figure class="highlight qml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> BrotherTao <span class="number">1.0</span></span><br><span class="line"><span class="title">Item</span> &#123;</span><br><span class="line">    <span class="title">BrotherTao</span> &#123;         <span class="comment">//实例化一个对象</span></span><br><span class="line">        <span class="attribute">id:</span><span class="string"> tao</span></span><br><span class="line">        <span class="attribute">onHungry</span>: &#123;     <span class="comment">//给信号写个槽函数</span></span><br><span class="line">            <span class="keyword">if</span> (foodName === <span class="string">"蛋炒饭"</span>) &#123;      <span class="comment">//示意一下，不要在意吃啥。</span></span><br><span class="line">                <span class="built_in">console</span>.log(<span class="string">"涛哥要吃蛋炒饭"</span>)</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (foodName === <span class="string">"水饺"</span>) &#123;</span><br><span class="line">                <span class="built_in">console</span>.log(<span class="string">"涛哥要吃水饺"</span>)</span><br><span class="line">            &#125; </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line">    <span class="title">Button</span> &#123;</span><br><span class="line">        <span class="attribute">onClicked</span>: &#123;</span><br><span class="line">            <span class="comment">//这个按钮按下的时候，涛哥开始唱歌</span></span><br><span class="line">            tao.sing();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title">Button</span> &#123;</span><br><span class="line">        <span class="attribute">onClicked</span>: &#123;</span><br><span class="line">            <span class="comment">//这个按钮按下的时候，涛哥开始打游戏</span></span><br><span class="line">            <span class="keyword">let</span> score = tao.sing(<span class="number">3</span>);</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">"涛哥打游戏次数"</span>， <span class="number">3</span>， <span class="string">"得分为"</span>, score)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="注册实例并使用"><a href="#注册实例并使用" class="headerlink" title="注册实例并使用"></a>注册实例并使用</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">BrotherTao tao;     <span class="comment">//C++中创建的实例</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//如果用QQ'u'ic'kView加载Qml</span></span><br><span class="line">QQuickView view;</span><br><span class="line">...</span><br><span class="line">view.rootContext()-&gt;setContextProperty(<span class="string">"tao"</span>, &amp;tao);    <span class="comment">//注意这个名字不要用大写字母开头，规则和Qml中的id不能用大写字母开头一样。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//如果用QQmlEngine加载Qml</span></span><br><span class="line">QQmlEngine engine;</span><br><span class="line">...</span><br><span class="line">engine..rootContext()-&gt;setContextProperty(<span class="string">"tao"</span>, &amp;tao); <span class="comment">//注意这个名字不要用大写字母开头，规则和Qml中的id不能用大写字母开头一样。</span></span><br></pre></td></tr></table></figure>

<figure class="highlight qml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//这种不用再import了</span></span><br><span class="line"><span class="title">Item</span> &#123;</span><br><span class="line">    <span class="title">Connections</span> &#123;        <span class="comment">//通过connectins连接信号</span></span><br><span class="line">        <span class="attribute">target</span>: tao     <span class="comment">//指定target</span></span><br><span class="line">        <span class="attribute">onHungry</span>: &#123;     <span class="comment">//给信号写个槽函数</span></span><br><span class="line">            <span class="keyword">if</span> (foodName === <span class="string">"蛋炒饭"</span>) &#123;      <span class="comment">//示意一下，不要在意吃啥。</span></span><br><span class="line">                <span class="built_in">console</span>.log(<span class="string">"涛哥要吃蛋炒饭"</span>)</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (foodName === <span class="string">"水饺"</span>) &#123;</span><br><span class="line">                <span class="built_in">console</span>.log(<span class="string">"涛哥要吃水饺"</span>)</span><br><span class="line">            &#125; </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line">    <span class="title">Button</span> &#123;</span><br><span class="line">        <span class="attribute">onClicked</span>: &#123;</span><br><span class="line">            <span class="comment">//这个按钮按下的时候，涛哥开始唱歌</span></span><br><span class="line">            tao.sing();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title">Button</span> &#123;</span><br><span class="line">        <span class="attribute">onClicked</span>: &#123;</span><br><span class="line">            <span class="comment">//这个按钮按下的时候，涛哥开始打游戏</span></span><br><span class="line">            <span class="keyword">let</span> score = tao.sing(<span class="number">3</span>);</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">"涛哥打游戏次数"</span>， <span class="number">3</span>， <span class="string">"得分为"</span>, score)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>




    </div>
    
    <div class="reward" ontouchstart>
    <div class="reward-wrap">赏
        <div class="reward-box">
            
            <span class="reward-type">
                <img class="alipay" src="/img/zhifubao.jpg"><b>支付宝打赏</b>
            </span>
            
            
            <span class="reward-type">
                <img class="wechat" src="/img/weixin.jpg"><b>微信打赏</b>
            </span>
            
        </div>
    </div>
    <p class="reward-tip">
        很有收获,请作者喝杯茶
    </p>
</div>
    
    <div class="post-footer">
        <div>
            
            转载声明：
            文章采用<a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议</a>进行许可, 转载请注明出处 © <a href="https://jaredtao.github.io" target="_blank">武威的涛哥</a>
            
            
        </div>
        <div>
            
        </div>
    </div>
</article>
<div class="article-nav prev-next-wrap clearfix">
    
    <a href="/2019/05/18/Qml/%E7%8E%A9%E8%BD%ACQml(6)-%E8%BF%9B%E5%BA%A6%E6%9D%A1%E5%AE%9A%E5%88%B6/" class="pre-post btn btn-default" title='玩转Qml(6)-进度条定制'>
        <i class="fa fa-angle-left fa-fw"></i><span class="hidden-lg">上一篇</span>
        <span class="hidden-xs">
            玩转Qml(6)-进度条定制</span>
    </a>
    
    
    <a href="/2019/05/12/Qml/%E7%8E%A9%E8%BD%ACQml(4)-I18n%E5%8A%A8%E6%80%81%E5%9B%BD%E9%99%85%E5%8C%96/" class="next-post btn btn-default" title='玩转Qml(4)-I18n动态国际化'>
        <span class="hidden-lg">下一篇</span>
        <span class="hidden-xs">
            玩转Qml(4)-I18n动态国际化</span><i class="fa fa-angle-right fa-fw"></i>
    </a>
    
</div>

<div id="comments">
    

<div id="vcomments" class="valine"></div>

<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="/assets/valine.min.js"></script>

<script>
new Valine({
    av: AV,
    el: '#vcomments',
    appId: 'qegD4552u6FU9HoNDvRsonko-gzGzoHsz',
    appKey: 'eitB2FV5n2qyMHcDM7x6EQpt',
    placeholder: '说点什么吧',
    notify: false,
    verify: true,
    avatar: 'mm',
    meta: 'nick,mail'.split(','),
    pageSize: '10',
    path: window.location.pathname,
    lang: 'zh-CN'.toLowerCase()
})
</script>


</div>


                </main>
                
                    <aside id="article-toc" role="navigation" class="col-md-4">
    <div class="widget">
        <h3 class="title">
            文章目录
        </h3>
        
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#简介"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#源码"><span class="toc-text">源码</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#C-访问Qml"><span class="toc-text">C++访问Qml</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#findChild"><span class="toc-text">findChild</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#QQmlComponent"><span class="toc-text">QQmlComponent</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Qml访问C"><span class="toc-text">Qml访问C++</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#注册类并使用"><span class="toc-text">注册类并使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#注册实例并使用"><span class="toc-text">注册实例并使用</span></a></li></ol></li></ol>
        
    </div>
</aside>
                
            </div>
        </div>
    </section>
    <footer class="main-footer">
    <div class="container">
        <div class="row">
        </div>
    </div>
</footer>
<a id="back-to-top" class="icon-btn hide">
    <i class="fa fa-chevron-up"></i>
</a>
    <div class="copyright">
    <div class="container">
        <div class="row">
            <div class="col-sm-12">
                <div class="busuanzi">
    
    访问量:
    <strong id="busuanzi_value_site_pv">
        <i class="fa fa-spinner fa-spin"></i>
    </strong>
    &nbsp; | &nbsp;
    访客数:
    <strong id="busuanzi_value_site_uv">
        <i class="fa fa-spinner fa-spin"></i>
    </strong>
    
</div>
            </div>
            <div class="col-sm-12">
                <span>Copyright &copy;
                    2019
                    
                </span> |
                <span>
                    Powered by <a href="//hexo.io" class="copyright-links" target="_blank" rel="nofollow">Hexo</a>
                </span> |
                <span>
                    Theme by <a href="//github.com/shenliyang/hexo-theme-snippet.git" class="copyright-links" target="_blank" rel="nofollow">Snippet</a>
                </span>
            </div>
        </div>
    </div>
</div>



<script src="/assets/tagcanvas.min.js?rev=2.9.js"></script>

<script>
var tagOption = {
    textColour: '#444', // 字体颜色
    outlineMethod: 'block', // 选中模式
    outlineColour: '#FFDAB9', // 选中模式的颜色
    interval: 30 || 30, // 动画帧之间的时间间隔，值越大，转动幅度越大
    textHeight: 13,
    outlineRadius: 3,
    freezeActive: true || '', // 选中的标签是否继续滚动
    frontSelect: true || '', // 不选标签云后部的标签
    initial: [0.1, -0.1],
    depth: 0.5,
    decel: 0.95,
    maxSpeed: 0.03,
    reverse: true || '', // 是否反向触发
    fadeIn: 500, // 进入动画时间
    wheelZoom: false || '' // 是否启用鼠标滚轮
}
TagCanvas.Start('tag-cloud-3d', '', tagOption);
</script>


<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>


<script src="/js/app.js?rev=@@hash.js"></script>

</body>
</html>